#include <stdlib.h>
#include "gd32f3x0.h"
#include "UART_Ctrl.h"

void UART_Config(void)
{
    usart_deinit(USART0);
    usart_word_length_set(USART0, USART_WL_8BIT);
    usart_stop_bit_set(USART0, USART_STB_1BIT);
    usart_parity_config(USART0, USART_PM_NONE);
    usart_baudrate_set(USART0, 115200U);
    usart_receive_config(USART0, USART_RECEIVE_ENABLE);
    usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);
    /* USART0 enable */
    usart_enable(USART0);

    usart_deinit(USART1);
    usart_word_length_set(USART1, USART_WL_8BIT);
    usart_stop_bit_set(USART1, USART_STB_1BIT);
    usart_parity_config(USART1, USART_PM_NONE);
    usart_baudrate_set(USART1, 115200U);
    usart_receive_config(USART1, USART_RECEIVE_ENABLE);
    usart_transmit_config(USART1, USART_TRANSMIT_ENABLE);
    /* USART1 enable */
    usart_enable(USART1);
    /* USART1 interrupt configuration */
    nvic_irq_enable(USART1_IRQn, 0, 0);
}

void UART_EnableTxIRQ(uint32_t USARTx)
{
    /* Enable the USARTx Transmit interrupt */
    usart_interrupt_enable(USARTx, USART_INT_TC);
    usart_interrupt_enable(USARTx, USART_INT_TBE);
}

void UART_DisableTxIRQ(uint32_t USARTx)
{
    /* Enable the USARTx Transmit interrupt */
    usart_interrupt_disable(USARTx, USART_INT_TC);
    usart_interrupt_disable(USARTx, USART_INT_TBE);
}

void UART_EnableDMATX(uint32_t USARTx)
{
    /* enable DMA channel */
    if(USARTx == USART0)
    {
        dma_channel_enable(DMA_CH1);
    }
    else
    {
        dma_channel_enable(DMA_CH3);
    }

    /* USART DMA enable for transmission and reception */
    usart_dma_transmit_config(USARTx, USART_DENT_ENABLE);
}

void UART_DisableDMATX(uint32_t USARTx)
{
    if(USARTx == USART0)
    {
        dma_flag_clear(DMA_CH1, DMA_FLAG_FTF);
        dma_channel_disable(DMA_CH1);
    }
    else
    {
        dma_flag_clear(DMA_CH3, DMA_FLAG_FTF);
        dma_channel_disable(DMA_CH3);
    }
    usart_dma_transmit_config(USARTx, USART_DENT_DISABLE);
}

int UART_DMATXDone(uint32_t USARTx)
{
    if(USARTx == USART0)
    {
        return dma_flag_get(DMA_CH1, DMA_FLAG_FTF);
    }
    else
    {
        return dma_flag_get(DMA_CH3, DMA_FLAG_FTF);
    }
}

void UART_TXDMAConfig(uint32_t USARTx, unsigned char* pTXDataBuf, int size)
{
    dma_parameter_struct dma_init_struct;
    dma_channel_enum dma_ch = DMA_CH1;
    
    /* deinitialize DMA channel1 */
    if(USARTx == USART1)
    {
        dma_ch = DMA_CH3;
    }
 
    dma_deinit(dma_ch);
    dma_struct_para_init(&dma_init_struct);
    dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL;
    dma_init_struct.memory_addr = (uint32_t)pTXDataBuf;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
    dma_init_struct.number = size;
    dma_init_struct.periph_addr = (uint32_t) &USART_TDATA(USARTx);
    dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
    dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
    dma_init(dma_ch, &dma_init_struct);

    /* configure DMA mode */
    dma_circulation_disable(dma_ch);
    dma_memory_to_memory_disable(dma_ch);
}

void UART_EnableRxIRQ(uint32_t USARTx)
{
    /* Enable the USARTx Receive interrupt:
     this interrupt is generated when the USARTx receive data register is not empty */
    usart_interrupt_enable(USARTx, USART_INT_RBNE);
}

void UART_DisableRxIRQ(uint32_t USARTx)
{
    /* Disable the USARTx Receive interrupt:
     this interrupt is generated when the USARTx receive data register is not empty */
    usart_interrupt_disable(USARTx, USART_INT_RBNE);
}

void UART_EnableDMARX(uint32_t USARTx)
{
    if(USARTx == USART0)
    {
        dma_channel_enable(DMA_CH2);
    }
    else
    {
        dma_channel_enable(DMA_CH4);
    }
    
    usart_dma_receive_config(USARTx, USART_DENR_ENABLE);
}

void UART_DisableDMARX(uint32_t USARTx)
{
    if(USARTx == USART0)
    {
        dma_flag_clear(DMA_CH2, DMA_FLAG_FTF);
        dma_channel_disable(DMA_CH2);
    }
    else
    {
        dma_flag_clear(DMA_CH4, DMA_FLAG_FTF);
        dma_channel_disable(DMA_CH4);
    }
    
    usart_dma_receive_config(USARTx, USART_DENR_DISABLE);
}

int UART_DMARXDone(uint32_t USARTx)
{
    if(USARTx == USART0)
    {
        return dma_flag_get(DMA_CH2, DMA_FLAG_FTF);
    }
    else
    {
        return dma_flag_get(DMA_CH4, DMA_FLAG_FTF);
    }
}

void UART_RXDMAConfig(uint32_t USARTx, unsigned char* pRXDataBuf, int size)
{
    dma_parameter_struct dma_init_struct;
    dma_channel_enum dma_ch = DMA_CH2;

    /* deinitialize DMA channel1 */
    if(USARTx == USART1)
    {
        dma_ch = DMA_CH4;
    }

    dma_deinit(dma_ch);
    dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;
    dma_init_struct.memory_addr = (uint32_t)pRXDataBuf;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
    dma_init_struct.number = size;
    dma_init_struct.periph_addr = (uint32_t) &USART_RDATA(USARTx);
    dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
    dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
    dma_init(dma_ch, &dma_init_struct);

    /* configure DMA mode */
    dma_circulation_disable(dma_ch);
    dma_memory_to_memory_disable(dma_ch);
}

void UART_Send(uint32_t USARTx, unsigned char* TXBuf, int TXLen)
{
    int SendIdx = 0;

    while(SendIdx < TXLen)
    {
        /* Wait until end of transmit */
        while(usart_flag_get(USARTx, USART_FLAG_TBE) == RESET)
        {
        }
        /* Write one byte in the USARTy Transmit Data Register */
        usart_data_transmit(USARTx, TXBuf[SendIdx]);
        SendIdx++;
    }
}

void UART_ConfigForUpgrade(uint32_t USARTx)
{
    UART_DisableRxIRQ(USARTx);
}
